import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from scipy.signal import butter, filtfilt, welch
import matplotlib.pyplot as plt
from matplotlib.widgets import Button, Slider
import json
import os
import time
import threading
from queue import Queue, Empty
from tensorflow.keras.models import Sequential, load_model
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping
import tensorflow as tf
import psutil
import gc

# 启用交互模式
plt.ion()

# 加载本地中文字体
try:
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体显示中文
    plt.rcParams['axes.unicode_minus'] = False  # 解决负号 '-' 显示为方块的问题
except Exception as e:
    print(f"加载字体失败: {e}")


class StateRecognizerML:
    def __init__(self):
        # 初始化机器学习模型（默认使用随机森林）
        self.model_type = "rf"  # rf: 随机森林, lstm: LSTM
        self.model = self._init_model()

        # 状态颜色映射
        self.state_colors = {
            "加速": "#FF6B6B",  # 红色
            "减速": "#4ECDC4",  # 青色
            "转弯": "#FFD166",  # 黄色
            "平缓行驶": "#06D6A0",  # 绿色
            "匀速行驶": "#118AB2",  # 蓝色
            "未知状态": "#6A0572"  # 紫色
        }

        # 定义阈值常量（用于特征提取）
        self.ACCELERATION_X_THRESHOLD_POS = 0.05  # 加速阈值
        self.ACCELERATION_X_THRESHOLD_NEG = -0.05  # 减速阈值
        self.GYROSCOPE_Z_VARIANCE_THRESHOLD = 50  # 转弯阈值
        self.ACCELERATION_VARIANCE_THRESHOLD = 0.1  # 平缓行驶阈值
        self.STATE_TRANSITION_THRESHOLD = 0.7  # 状态转换阈值

        # 低通滤波器参数
        self.filter_order = 3  # Butterworth滤波器阶数
        self.cutoff_freq = 5.0  # 截止频率
        self.sampling_rate = 100.0  # 根据数据采样间隔调整，假设为100Hz

        # 设置更新速度（新增行，确保在_init_controls前定义）
        self.update_speed = 0.5  # 默认更新速度

        # 初始化实时绘图
        self.fig, self.axes = plt.subplots(2, 1, figsize=(14, 10), gridspec_kw={'height_ratios': [2, 1]})
        plt.subplots_adjust(bottom=0.2)
        self.fig.suptitle('车辆行驶状态实时监测', fontsize=16, fontweight='bold')

        # 加速度绘图初始化（使用更大的缓冲区）
        self.acc_buffer_size = int(5 * self.sampling_rate)  # 5秒数据缓冲区
        self.acc_x_buffer = np.zeros(self.acc_buffer_size)
        self.acc_y_buffer = np.zeros(self.acc_buffer_size)
        self.acc_z_buffer = np.zeros(self.acc_buffer_size)
        self.gyro_z_buffer = np.zeros(self.acc_buffer_size)
        self.time_steps = np.arange(self.acc_buffer_size)
        self.buffer_pointer = 0
        self.last_update_time = time.time()

        # 加速度图表
        self.acc_lines = []
        self.acc_lines.append(
            self.axes[0].plot(self.time_steps, self.acc_x_buffer,
                              label='加速度X轴', color='#EF476F', linewidth=1.5)[0])
        self.acc_lines.append(
            self.axes[0].plot(self.time_steps, self.acc_y_buffer,
                              label='加速度Y轴', color='#06D6A0', linewidth=1.5)[0])
        self.acc_lines.append(
            self.axes[0].plot(self.time_steps, self.acc_z_buffer,
                              label='加速度Z轴', color='#118AB2', linewidth=1.5)[0])

        self.axes[0].set_xlabel('时间步 (0.01秒/步)', fontsize=10)
        self.axes[0].set_ylabel('加速度 (g)', fontsize=10)
        self.axes[0].set_title('三轴加速度数据', fontsize=12, fontweight='bold')
        self.axes[0].legend(loc='upper right', fontsize=9)
        self.axes[0].grid(True, linestyle='--', alpha=0.7)
        self.axes[0].set_xlim(0, self.acc_buffer_size)
        self.axes[0].set_ylim(-2, 2)  # 固定Y轴范围

        # 陀螺仪图表
        self.gyro_line = self.axes[1].plot(
            self.time_steps, self.gyro_z_buffer,
            label='陀螺仪Z轴', color='#FFD166', linewidth=1.5)[0]

        self.axes[1].set_xlabel('时间步 (0.01秒/步)', fontsize=10)
        self.axes[1].set_ylabel('角速度 (deg/s)', fontsize=10)
        self.axes[1].set_title('Z轴角速度数据', fontsize=12, fontweight='bold')
        self.axes[1].legend(loc='upper right', fontsize=9)
        self.axes[1].grid(True, linestyle='--', alpha=0.7)
        self.axes[1].set_xlim(0, self.acc_buffer_size)
        self.axes[1].set_ylim(-200, 200)  # 固定Y轴范围

        # 状态显示
        self.state_text = self.fig.text(
            0.5, 0.05, '状态: 等待数据 | 当前模型: 随机森林',
            ha='center', fontsize=12, fontweight='bold',
            bbox=dict(facecolor=self.state_colors["未知状态"], alpha=0.8, boxstyle='round,pad=0.5'))

        # 性能监控
        self.perf_text = self.fig.text(0.02, 0.02, '', fontsize=9, color='#555555')

        # 用户交互控件
        self._init_controls()

        # 初始化数据存储
        self.acc_x_history = []
        self.acc_y_history = []
        self.acc_z_history = []
        self.gyro_z_history = []
        self.window_count = 0
        self.last_state = "未知状态"

        # 多线程支持
        self.data_queue = Queue(maxsize=20)  # 增大队列容量
        self.processing_running = True
        self.thread = None
        self.lock = threading.Lock()

        # LSTM模型参数
        self.sequence_length = int(1.5 * self.sampling_rate)  # 1.5秒序列长度
        self.feature_dim = 4  # 加速度3轴 + 陀螺仪Z轴

        # 初始化模型路径
        self.model_dir = "saved_models"
        os.makedirs(self.model_dir, exist_ok=True)

        # 初始化性能计数器
        self.processed_count = 0
        self.start_time = time.time()

    def _init_model(self):
        """初始化模型（随机森林或LSTM）"""
        if self.model_type == "rf":
            print("初始化随机森林模型...")
            return RandomForestClassifier(
                n_estimators=100,
                max_depth=10,
                min_samples_split=5,
                random_state=42,
                n_jobs=-1  # 使用所有CPU核心
            )
        else:
            print("初始化LSTM模型...")
            # LSTM模型结构
            model = Sequential()
            model.add(LSTM(64, return_sequences=True,
                           input_shape=(self.sequence_length, self.feature_dim),
                           kernel_initializer='glorot_uniform'))
            model.add(Dropout(0.3))
            model.add(LSTM(64, kernel_initializer='glorot_uniform'))
            model.add(Dropout(0.3))
            model.add(Dense(32, activation='relu'))
            model.add(Dense(5, activation='softmax'))  # 5种行驶状态

            model.compile(
                optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
                loss='sparse_categorical_crossentropy',
                metrics=['accuracy']
            )
            return model

    def _init_controls(self):
        """初始化用户交互控件"""
        # 按钮位置设置
        ax_pause = plt.axes([0.10, 0.12, 0.12, 0.05])
        ax_resume = plt.axes([0.23, 0.12, 0.12, 0.05])
        ax_rf = plt.axes([0.36, 0.12, 0.12, 0.05])
        ax_lstm = plt.axes([0.49, 0.12, 0.12, 0.05])
        ax_save = plt.axes([0.62, 0.12, 0.12, 0.05])
        ax_load = plt.axes([0.75, 0.12, 0.12, 0.05])
        ax_speed = plt.axes([0.15, 0.05, 0.7, 0.03])

        # 暂停按钮
        self.btn_pause = Button(ax_pause, '暂停', color='#F8F9FA', hovercolor='#E9ECEF')
        self.btn_pause.label.set_fontweight('bold')
        self.btn_pause.on_clicked(self._pause_callback)

        # 继续按钮
        self.btn_resume = Button(ax_resume, '继续', color='#F8F9FA', hovercolor='#E9ECEF')
        self.btn_resume.label.set_fontweight('bold')
        self.btn_resume.on_clicked(self._resume_callback)
        self.btn_resume.ax.set_visible(False)  # 初始隐藏

        # 随机森林模型按钮
        self.btn_rf = Button(ax_rf, 'RF模型', color='#DEE2E6', hovercolor='#ADB5BD')
        self.btn_rf.label.set_fontweight('bold')
        self.btn_rf.on_clicked(self._rf_model_callback)

        # LSTM模型按钮
        self.btn_lstm = Button(ax_lstm, 'LSTM模型', color='#E9ECEF', hovercolor='#DEE2E6')
        self.btn_lstm.label.set_fontweight('bold')
        self.btn_lstm.on_clicked(self._lstm_model_callback)

        # 保存模型按钮
        self.btn_save = Button(ax_save, '保存模型', color='#C7F9CC', hovercolor='#80ED99')
        self.btn_save.label.set_fontweight('bold')
        self.btn_save.on_clicked(self._save_model_callback)

        # 加载模型按钮
        self.btn_load = Button(ax_load, '加载模型', color='#A9DEF9', hovercolor='#48BFE3')
        self.btn_load.label.set_fontweight('bold')
        self.btn_load.on_clicked(self._load_model_callback)

        # 速度滑块
        self.speed_slider = Slider(
            ax_speed, '更新速度 (秒/窗口)', 0.1, 2.0,
            valinit=self.update_speed, valfmt='%1.1f 秒',
            color='#48BFE3', track_color='#E9ECEF')
        self.speed_slider = self.speed_slider  # 保持兼容性
        self.speed_slider.on_changed(self._speed_changed_callback)

    def _pause_callback(self, event):
        """暂停按钮回调"""
        with self.lock:
            self.processing_running = False
            self.btn_pause.ax.set_visible(False)
            self.btn_resume.ax.set_visible(True)
            self._update_state_display('已暂停', self.last_state)
            print("处理已暂停")

    def _resume_callback(self, event):
        """继续按钮回调"""
        with self.lock:
            self.processing_running = True
            self.btn_pause.ax.set_visible(True)
            self.btn_resume.ax.set_visible(False)
            self._update_state_display('运行中', self.last_state)
            print("处理已恢复")

    def _rf_model_callback(self, event):
        """切换到随机森林模型"""
        with self.lock:
            self.model_type = "rf"
            self.model = self._init_model()
            self._update_state_display('运行中', self.last_state)
            print("已切换到随机森林模型")

    def _lstm_model_callback(self, event):
        """切换到LSTM模型"""
        with self.lock:
            self.model_type = "lstm"
            self.model = self._init_model()
            self._update_state_display('运行中', self.last_state)
            print("已切换到LSTM模型")

    def _save_model_callback(self, event):
        """保存当前模型"""
        model_path = os.path.join(self.model_dir, f"vehicle_state_model_{self.model_type}.h5")

        try:
            if self.model_type == "rf":
                import joblib
                joblib.dump(self.model, model_path)
            else:
                self.model.save(model_path)

            print(f"模型已保存到: {model_path}")
            self.perf_text.set_text(f"模型已保存: {model_path}")
        except Exception as e:
            print(f"保存模型失败: {e}")
            self.perf_text.set_text(f"保存失败: {str(e)}")

    def _load_model_callback(self, event):
        """加载保存的模型"""
        model_path = os.path.join(self.model_dir, f"vehicle_state_model_{self.model_type}.h5")

        if not os.path.exists(model_path):
            print(f"模型文件不存在: {model_path}")
            self.perf_text.set_text("错误: 模型文件不存在")
            return

        try:
            if self.model_type == "rf":
                import joblib
                self.model = joblib.load(model_path)
            else:
                self.model = load_model(model_path)

            print(f"已从 {model_path} 加载模型")
            self.perf_text.set_text(f"模型已加载: {model_path}")
        except Exception as e:
            print(f"加载模型失败: {e}")
            self.perf_text.set_text(f"加载失败: {str(e)}")

    def _speed_changed_callback(self, val):
        """更新速度滑块回调"""
        with self.lock:
            self.update_speed = val
            print(f"更新速度已设置为: {val}秒")

    def _update_state_display(self, status, state):
        """更新状态显示"""
        color = self.state_colors.get(state, self.state_colors["未知状态"])
        self.state_text.set_text(f'状态: {status} | 当前模型: {self.model_type} | 预测状态: {state}')
        self.state_text.set_bbox(dict(facecolor=color, alpha=0.8, boxstyle='round,pad=0.5'))

    def _update_perf_display(self):
        """更新性能显示"""
        elapsed = time.time() - self.start_time
        mem_usage = psutil.Process().memory_info().rss / (1024 * 1024)  # MB
        fps = self.processed_count / elapsed if elapsed > 0 else 0

        text = (
            f"处理窗口: {self.processed_count} | "
            f"速度: {fps:.1f} FPS | "
            f"内存: {mem_usage:.1f} MB | "
            f"队列: {self.data_queue.qsize()}"
        )
        self.perf_text.set_text(text)

    def extract_sensor_data(self, buff_pool):
        """从缓冲池数据中提取加速度和陀螺仪数据"""
        if not buff_pool:
            return None, None, None, None

        acceleration_x = []
        acceleration_y = []
        acceleration_z = []
        gyroscope_z = []

        for item in buff_pool:
            # 提取滤波后的加速度数据
            acc = item.get('filtered_acceleration', {})
            acceleration_x.append(acc.get('x', 0))
            acceleration_y.append(acc.get('y', 0))
            acceleration_z.append(acc.get('z', 0))

            # 提取滤波后的陀螺仪z轴数据
            gyro = item.get('filtered_gyroscope', {})
            gyroscope_z.append(gyro.get('z', 0))

        return (
            np.array(acceleration_x),
            np.array(acceleration_y),
            np.array(acceleration_z),
            np.array(gyroscope_z)
        )

    def preprocess_data(self, acceleration_x, acceleration_y, acceleration_z, gyroscope_z):
        """数据预处理：去噪、校准和窗口分割"""
        # 数据长度检查
        min_length = int(0.5 * self.sampling_rate)  # 最少0.5秒数据
        if len(acceleration_x) < min_length:
            return None

        # 创建 Butterworth 低通滤波器
        nyquist = 0.5 * self.sampling_rate
        normal_cutoff = self.cutoff_freq / nyquist
        b, a = butter(self.filter_order, normal_cutoff, btype='low', analog=False)

        # 应用滤波器去除高频噪声
        def safe_filtfilt(data):
            if len(data) > self.filter_order * 3:  # 滤波要求的最小数据长度
                return filtfilt(b, a, data)
            return data

        filtered_acc_x = safe_filtfilt(acceleration_x)
        filtered_acc_y = safe_filtfilt(acceleration_y)
        filtered_acc_z = safe_filtfilt(acceleration_z)
        filtered_gyro_z = safe_filtfilt(gyroscope_z)

        # 消除重力影响
        dynamic_acc_x = filtered_acc_x - np.mean(filtered_acc_x)
        dynamic_acc_y = filtered_acc_y - np.mean(filtered_acc_y)
        dynamic_acc_z = filtered_acc_z - np.mean(filtered_acc_z)

        # 将数据分割为1.5秒的窗口
        window_size = int(1 * self.sampling_rate)
        windows = {
            'acceleration_x': [dynamic_acc_x[i:i + window_size] for i in
                               range(0, len(dynamic_acc_x), window_size // 2)],
            'acceleration_y': [dynamic_acc_y[i:i + window_size] for i in
                               range(0, len(dynamic_acc_y), window_size // 2)],
            'acceleration_z': [dynamic_acc_z[i:i + window_size] for i in
                               range(0, len(dynamic_acc_z), window_size // 2)],
            'gyroscope_z': [filtered_gyro_z[i:i + window_size] for i in
                            range(0, len(filtered_gyro_z), window_size // 2)]
        }

        # 过滤掉不完整的窗口
        valid_windows = min(len(windows['acceleration_x']), len(windows['acceleration_y']),
                            len(windows['acceleration_z']), len(windows['gyroscope_z']))

        for key in windows:
            windows[key] = windows[key][:valid_windows]

        return windows

    def extract_features(self, window_data):
        """特征提取：从每个时间窗口提取时域和频域特征"""
        features = {}
        data_len = len(window_data['acceleration_x'])

        # 仅当窗口数据完整时提取特征
        min_length = int(1.0 * self.sampling_rate)  # 最少1秒数据
        if data_len < min_length:
            return None

        # 时域特征
        acc_x = window_data['acceleration_x']
        acc_y = window_data['acceleration_y']
        acc_z = window_data['acceleration_z']
        gyro_z = window_data['gyroscope_z']

        # 基本统计特征
        for axis, data in zip(['x', 'y', 'z'], [acc_x, acc_y, acc_z]):
            features[f'acc_{axis}_mean'] = np.mean(data)
            features[f'acc_{axis}_std'] = np.std(data)
            features[f'acc_{axis}_max'] = np.max(data)
            features[f'acc_{axis}_min'] = np.min(data)
            features[f'acc_{axis}_ptp'] = np.ptp(data)  # 峰峰值
            features[f'acc_{axis}_var'] = np.var(data)  # 方差
            features[f'acc_{axis}_rms'] = np.sqrt(np.mean(np.square(data)))  # RMS

        # 陀螺仪特征
        features['gyro_z_mean'] = np.mean(gyro_z)
        features['gyro_z_std'] = np.std(gyro_z)
        features['gyro_z_max'] = np.max(gyro_z)
        features['gyro_z_min'] = np.min(gyro_z)
        features['gyro_z_ptp'] = np.ptp(gyro_z)
        features['gyro_z_var'] = np.var(gyro_z)
        features['gyro_z_rms'] = np.sqrt(np.mean(np.square(gyro_z)))

        # 组合特征
        features['acc_magnitude'] = np.mean(np.sqrt(acc_x ** 2 + acc_y ** 2 + acc_z ** 2))
        features['acc_xy_corr'] = np.corrcoef(acc_x, acc_y)[0, 1]
        features['acc_xz_corr'] = np.corrcoef(acc_x, acc_z)[0, 1]

        # 频域特征
        if data_len > 10:  # FFT要求的最小数据长度
            def calc_fft(data):
                fft_vals = np.abs(np.fft.rfft(data))
                freqs = np.fft.rfftfreq(len(data), d=1.0 / self.sampling_rate)
                return fft_vals, freqs

            # 加速度频域特征
            for axis, data in zip(['x', 'y', 'z'], [acc_x, acc_y, acc_z]):
                fft_vals, freqs = calc_fft(data)
                if len(fft_vals) > 1:
                    # 主频位置和幅度
                    idx = np.argmax(fft_vals[1:]) + 1
                    features[f'acc_{axis}_freq'] = freqs[idx]
                    features[f'acc_{axis}_amp'] = fft_vals[idx]

            # 陀螺仪频域特征
            fft_vals, freqs = calc_fft(gyro_z)
            if len(fft_vals) > 1:
                idx = np.argmax(fft_vals[1:]) + 1
                features['gyro_z_freq'] = freqs[idx]
                features['gyro_z_amp'] = fft_vals[idx]

        return features

    def generate_labels(self, window_data):
        """使用规则方法生成标签（用于训练数据标注）"""
        # 计算时域特征
        acc_x = window_data['acceleration_x']
        gyro_z = window_data['gyroscope_z']

        acc_x_mean = np.mean(acc_x)
        acc_x_variance = np.var(acc_x)
        gyro_z_variance = np.var(gyro_z)
        gyro_z_max = np.max(np.abs(gyro_z))

        # 状态检测阈值
        is_accelerating = acc_x_mean > self.ACCELERATION_X_THRESHOLD_POS
        is_decelerating = acc_x_mean < self.ACCELERATION_X_THRESHOLD_NEG
        is_turning = gyro_z_variance > self.GYROSCOPE_Z_VARIANCE_THRESHOLD or gyro_z_max > 100
        is_smooth = acc_x_variance < self.ACCELERATION_VARIANCE_THRESHOLD

        # 状态优先级处理
        if is_turning:
            # 转弯状态优先级最高
            if is_accelerating:
                return "加速转弯"
            elif is_decelerating:
                return "减速转弯"
            return "转弯"

        if is_accelerating:
            return "加速"

        if is_decelerating:
            return "减速"

        if is_smooth:
            return "平缓行驶"

        return "匀速行驶"

    def prepare_dataset(self, all_windows_data):
        """准备训练数据集（支持LSTM格式）"""
        X = []
        y = []
        state_map = {"加速": 0, "减速": 1, "转弯": 2, "平缓行驶": 3,
                     "匀速行驶": 4, "加速转弯": 2, "减速转弯": 2}  # 组合状态映射到基础状态

        for window_data in all_windows_data:
            # 提取特征
            features = self.extract_features(window_data)
            if features is None:
                continue

            # 生成标签
            label = self.generate_labels(window_data)
            y.append(state_map.get(label, 4))  # 默认匀速

            # 根据模型类型准备数据
            if self.model_type == "rf":
                X.append(list(features.values()))
            else:
                # LSTM需要3D输入格式: [样本数, 时间步, 特征数]
                seq_data = np.column_stack((
                    window_data['acceleration_x'],
                    window_data['acceleration_y'],
                    window_data['acceleration_z'],
                    window_data['gyroscope_z']
                ))
                X.append(seq_data)

        if self.model_type == "rf":
            return np.array(X), np.array(y)
        else:
            # 转换为LSTM所需的格式
            return np.array(X), np.array(y)  # 对于LSTM使用稀疏分类

    def train_model(self, X_train, y_train, X_val=None, y_val=None):
        """训练机器学习模型"""
        if self.model_type == "rf":
            self.model.fit(X_train, y_train)
            print("随机森林训练完成")
        else:
            # LSTM模型训练
            early_stop = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)

            # 验证数据
            if X_val is None or y_val is None:
                X_train, X_val, y_train, y_val = train_test_split(
                    X_train, y_train, test_size=0.2, random_state=42)

            self.model.fit(
                X_train, y_train,
                validation_data=(X_val, y_val),
                epochs=50,
                batch_size=32,
                callbacks=[early_stop],
                verbose=1
            )
            print("LSTM训练完成")
        return self.model

    def evaluate_model(self, X_test, y_test):
        """评估模型性能"""
        if self.model_type == "rf":
            y_pred = self.model.predict(X_test)
            return accuracy_score(y_test, y_pred)
        else:
            # 对于LSTM使用稀疏分类
            y_pred = np.argmax(self.model.predict(X_test), axis=1)
            return accuracy_score(y_test, y_pred)

    def predict_states(self, new_window_data):
        """预测新数据的行驶状态"""
        state_map = {
            0: "加速",
            1: "减速",
            2: "转弯",
            3: "平缓行驶",
            4: "匀速行驶"
        }

        # 检查数据长度
        min_length = int(1.0 * self.sampling_rate)
        if len(new_window_data['acceleration_x']) < min_length:
            return "数据不足", 0.0

        # 提取特征
        features = self.extract_features(new_window_data)
        if features is None:
            return "无效特征", 0.0

        # 预测状态
        if self.model_type == "rf":
            proba = self.model.predict_proba([list(features.values())])[0]
            pred_idx = np.argmax(proba)
            confidence = np.max(proba)
            return state_map.get(pred_idx, "未知状态"), confidence
        else:
            # 准备LSTM输入数据
            seq_data = np.column_stack((
                new_window_data['acceleration_x'],
                new_window_data['acceleration_y'],
                new_window_data['acceleration_z'],
                new_window_data['gyroscope_z']
            ))
            # 确保序列长度正确
            if len(seq_data) > self.sequence_length:
                seq_data = seq_data[:self.sequence_length]
            elif len(seq_data) < self.sequence_length:
                # 填充序列
                pad_len = self.sequence_length - len(seq_data)
                seq_data = np.pad(seq_data, ((0, pad_len), (0, 0)), mode='constant')

            proba = self.model.predict(np.array([seq_data]))[0]
            pred_idx = np.argmax(proba)
            confidence = np.max(proba)
            return state_map.get(pred_idx, "未知状态"), confidence

    def update_buffer(self, acc_x, acc_y, acc_z, gyro_z):
        """更新循环缓冲区（优化版）"""
        data_len = len(acc_x)
        if data_len == 0:
            return

        # 计算写入位置
        start_idx = self.buffer_pointer
        end_idx = self.buffer_pointer + data_len
        buffer_size = self.acc_buffer_size

        # 情况1：数据可以完全放入缓冲区尾部
        if end_idx <= buffer_size:
            self.acc_x_buffer[start_idx:end_idx] = acc_x
            self.acc_y_buffer[start_idx:end_idx] = acc_y
            self.acc_z_buffer[start_idx:end_idx] = acc_z
            self.gyro_z_buffer[start_idx:end_idx] = gyro_z
            self.buffer_pointer = end_idx % buffer_size

        # 情况2：数据需要环绕到缓冲区开头
        else:
            # 第一部分：从指针到缓冲区末尾
            part1_len = buffer_size - start_idx
            self.acc_x_buffer[start_idx:] = acc_x[:part1_len]
            self.acc_y_buffer[start_idx:] = acc_y[:part1_len]
            self.acc_z_buffer[start_idx:] = acc_z[:part1_len]
            self.gyro_z_buffer[start_idx:] = gyro_z[:part1_len]

            # 第二部分：从缓冲区开头开始
            part2_len = data_len - part1_len
            self.acc_x_buffer[:part2_len] = acc_x[part1_len:]
            self.acc_y_buffer[:part2_len] = acc_y[part1_len:]
            self.acc_z_buffer[:part2_len] = acc_z[part1_len:]
            self.gyro_z_buffer[:part2_len] = gyro_z[part1_len:]

            self.buffer_pointer = part2_len

    def update_plot(self):
        """更新实时绘图（优化性能）"""
        # 限制更新频率（最多每秒30次）
        current_time = time.time()
        if current_time - self.last_update_time < 0.033:  # ~30 FPS
            return
        self.last_update_time = current_time

        # 更新加速度数据
        self.acc_lines[0].set_ydata(self.acc_x_buffer)
        self.acc_lines[1].set_ydata(self.acc_y_buffer)
        self.acc_lines[2].set_ydata(self.acc_z_buffer)

        # 更新陀螺仪数据
        self.gyro_line.set_ydata(self.gyro_z_buffer)

        # 仅在有显著变化时重绘图
        self.fig.canvas.draw_idle()
        self.fig.canvas.flush_events()

    def processing_thread(self, all_windows_data):
        """数据处理线程函数（线程安全）"""
        try:
            for i, window_data in enumerate(all_windows_data):
                # 检查处理状态
                with self.lock:
                    if not self.processing_running:
                        time.sleep(0.1)
                        continue

                # 预测状态
                predicted_state, confidence = self.predict_states(window_data)

                # 状态平滑处理（避免快速切换）
                if confidence < self.STATE_TRANSITION_THRESHOLD:
                    predicted_state = self.last_state
                else:
                    self.last_state = predicted_state

                # 将数据放入队列
                self.data_queue.put((window_data, predicted_state, confidence))

                # 更新计数
                self.processed_count += 1

                # 控制更新速度
                time.sleep(self.update_speed)

                # 定期清理内存
                if self.processed_count % 50 == 0:
                    gc.collect()

        except Exception as e:
            print(f"处理线程异常: {e}")
            with self.lock:
                self.processing_running = False
                self._update_state_display('错误', f"异常: {str(e)}")

    def start_real_time_processing(self, all_windows_data):
        """启动实时处理线程"""
        # 停止现有线程
        if self.thread and self.thread.is_alive():
            with self.lock:
                self.processing_running = False
            self.thread.join(timeout=1.0)

        # 重置状态
        with self.lock:
            self.processing_running = True
            self.btn_pause.ax.set_visible(True)
            self.btn_resume.ax.set_visible(False)
            self._update_state_display('运行中', '等待数据')
            self.processed_count = 0
            self.start_time = time.time()

        # 启动新线程
        self.thread = threading.Thread(
            target=self.processing_thread,
            args=(all_windows_data,),
            daemon=True
        )
        self.thread.start()
        print("实时处理线程已启动")

    def process_queue_data(self):
        """处理队列中的数据（在主线程调用）"""
        processed = 0
        max_process = 5  # 每次最多处理5个数据点

        while processed < max_process:
            try:
                # 非阻塞获取数据
                window_data, predicted_state, confidence = self.data_queue.get_nowait()
                processed += 1

                # 更新历史数据（限制存储5个窗口）
                self.acc_x_history.append(window_data['acceleration_x'])
                self.acc_y_history.append(window_data['acceleration_y'])
                self.acc_z_history.append(window_data['acceleration_z'])
                self.gyro_z_history.append(window_data['gyroscope_z'])

                if len(self.acc_x_history) > 5:
                    self.acc_x_history.pop(0)
                    self.acc_y_history.pop(0)
                    self.acc_z_history.pop(0)
                    self.gyro_z_history.pop(0)

                # 更新缓冲区
                self.update_buffer(
                    window_data['acceleration_x'],
                    window_data['acceleration_y'],
                    window_data['acceleration_z'],
                    window_data['gyroscope_z']
                )

                # 更新状态显示
                with self.lock:
                    self._update_state_display('运行中', predicted_state)

                # 更新性能显示
                self._update_perf_display()

            except Empty:
                break
            except Exception as e:
                print(f"处理队列数据错误: {e}")

        # 定期更新绘图
        if processed > 0:
            self.update_plot()

    def cleanup(self):
        """资源清理"""
        with self.lock:
            self.processing_running = False

        if self.thread and self.thread.is_alive():
            self.thread.join(timeout=1.0)

        plt.close(self.fig)
        print("资源已清理")